package pl.mchaniewski.ryneczek.web.admin;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;

import org.primefaces.model.DualListModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;

import pl.mchaniewski.ryneczek.pojo.Company;
import pl.mchaniewski.ryneczek.pojo.Index;
import pl.mchaniewski.ryneczek.services.CompanyService;
import pl.mchaniewski.ryneczek.services.IndexService;
import pl.mchaniewski.ryneczek.utilities.FacesMessageUtil;
import pl.mchaniewski.ryneczek.utilities.I18nUtil;
import pl.mchaniewski.ryneczek.utilities.NavigationUtil;
import pl.mchaniewski.ryneczek.web.FormButton;

@Component
@Scope("request")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public class IndexCompanyListBean extends FormButton {
    private static final Logger logger = LoggerFactory
            .getLogger(IndexCompanyListBean.class);
    private CompanyService companyService;
    private IndexService indexService;
    private String selectedIndex;
    private List<Index> indicesList;
    private DualListModel<String> companies;

    /* Form parameters */
    private String name;

    @Autowired
    public void setCompanyService(CompanyService companyService) {
        this.companyService = companyService;
    }

    @Autowired
    public void setIndexService(IndexService indexService) {
        this.indexService = indexService;
    }

    public DualListModel<String> getCompanies() {
        return companies;
    }

    public void setCompanies(DualListModel<String> companies) {
        this.companies = companies;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Index> getIndicesList() {
        return indicesList;
    }

    public String getSelectedIndex() {
        return selectedIndex;
    }

    public void setSelectedIndex(String selectedIndex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Set index to: {}", selectedIndex);
        }

        this.selectedIndex = selectedIndex;
    }

    @PostConstruct
    public void init() {
        if (logger.isDebugEnabled()) {
            logger.debug("Init is called.");
        }

        indicesList = indexService.findAll();
        if (indicesList != null) {
            List<String> missingIndices = new ArrayList<String>(
                    Arrays.asList(Index.OUT_OF_SYSTEM_INDICES));
            for (Iterator<Index> it = indicesList.iterator(); it.hasNext();) {
                String next = it.next().getName();
                if (missingIndices.contains(next)) {
                    missingIndices.remove(next);
                }
            }

            for (String missingIndex : missingIndices) {
                indexService.createNewIndex(missingIndex);
            }
        }
        indicesList = indexService.findAll();

        if (getSelectedIndex() == null || getSelectedIndex().equals("")) {
            setDualList((getIndicesList().size() > 0) ? getIndicesList().get(0)
                    : null);
        } else {
            setDualList(getSelectedIndex());
        }
    }

    private Index getIndexByName(String indexName) {
        if (logger.isDebugEnabled()) {
            logger.debug("Checking list for {} index", indexName);
        }

        Index index = null;
        for (Index i : getIndicesList()) {
            if (i.getName().equals(indexName)) {
                index = i;
                break;
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Result: {}", index == null ? "NULL" : index.getName());
        }

        return index;
    }

    private void setDualList(String indexName) {
        Index index = getIndexByName(indexName);

        if (index == null) {
            return;
        } else {
            setDualList(index);
        }
    }

    private void setDualList(Index index) {
        if (logger.isDebugEnabled()) {
            logger.debug("Updating dual list. Input index: {}",
                    index != null ? index.getName() : null);
        }

        List<String> source = new ArrayList<String>();
        List<String> target = new ArrayList<String>();

        if (index != null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Index wasn't null.");
            }

            List<Company> companies = companyService.findAll();
            for (Company c : companies) {
                source.add(c.getName());
            }

            Set<Company> companiesInIndex = index.getCompanies();
            for (Iterator<Company> it = companiesInIndex.iterator(); it
                    .hasNext();) {
                target.add(it.next().getName());
            }

            source.removeAll(target);

            if (logger.isDebugEnabled()) {
                logger.debug("Number of companies in index: {} Rest: {}",
                        target.size(), source.size());
            }
        }

        Collections.sort(source, String.CASE_INSENSITIVE_ORDER);
        Collections.sort(target, String.CASE_INSENSITIVE_ORDER);
        companies = new DualListModel<String>(source, target);
    }

    public String add() {
        if (logger.isDebugEnabled()) {
            logger.debug("Triggered add()");
        }

        if (getName() == null || getName().length() < 1
                || getName().length() > 15) {
            FacesMessageUtil.addMessage(I18nUtil
                    .getLocalizedMessage("indexcompanylistbean.indexName"),
                    FacesMessage.SEVERITY_ERROR);

            return NavigationUtil.SAME_PAGE;
        } else {
            for (Index i : getIndicesList()) {
                if (i.getName().equals(getName())) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Index with name {} already exists.",
                                getName());
                    }

                    FacesMessageUtil
                            .addMessage(
                                    I18nUtil.getLocalizedMessage("indexcompanylistbean.indexAleadyExists"),
                                    FacesMessage.SEVERITY_ERROR);

                    return NavigationUtil.SAME_PAGE;
                }
            }

            if (indexService.createNewIndex(getName()) != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Index {} created.", getName());
                }

                init();

                FacesMessageUtil.addMessage(I18nUtil
                        .getLocalizedMessage("indexcompanylistbean.created"),
                        FacesMessage.SEVERITY_INFO);
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Index {} not created.", getName());
                }

                FacesMessageUtil
                        .addMessage(
                                I18nUtil.getLocalizedMessage("indexcompanylistbean.notCreated"),
                                FacesMessage.SEVERITY_ERROR);
            }
        }

        return NavigationUtil.SAME_PAGE;
    }

    public void select() {
        if (logger.isDebugEnabled()) {
            logger.debug("Triggered select()");
        }

        setDualList(getSelectedIndex());
    }

    public String save() {
        if (logger.isDebugEnabled()) {
            logger.debug("Triggered save())");
        }

        Index selectedIndx = getIndexByName(getSelectedIndex());
        if (selectedIndx == null) {
            if (logger.isDebugEnabled()) {
                logger.debug("None indices selected.");
            }

            FacesMessageUtil
                    .addMessage(
                            getButton(),
                            I18nUtil.getLocalizedMessage("indexcompanylistbean.nothingSelected"),
                            FacesMessage.SEVERITY_ERROR);

            return NavigationUtil.SAME_PAGE;
        }

        Set<Company> companySet = new HashSet<Company>(0);
        for (String s : getCompanies().getTarget()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Adding {} company to {} index.", s,
                        selectedIndx.getName());
            }

            Company tempComp = companyService.findByName(s);
            if (tempComp == null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Company doesn't exist.");
                }

                continue;
            } else {
                companySet.add(tempComp);
            }
        }

        selectedIndx.setCompanies(companySet);
        setDualList(selectedIndx);
        if (indexService.save(selectedIndx) != null) {
            FacesMessageUtil.addMessage(getButton(),
                    I18nUtil.getLocalizedMessage("indexcompanylistbean.saved"),
                    FacesMessage.SEVERITY_INFO);
        } else {
            FacesMessageUtil.addMessage(getButton(), I18nUtil
                    .getLocalizedMessage("indexcompanylistbean.notSaved"),
                    FacesMessage.SEVERITY_ERROR);
        }

        return NavigationUtil.SAME_PAGE;
    }

    public String remove() {
        if (getSelectedIndex() == null) {
            FacesMessageUtil.addMessage(getButton(), I18nUtil
                    .getLocalizedMessage("indexcompanylistbean.notSelected"),
                    FacesMessage.SEVERITY_ERROR);

            return NavigationUtil.SAME_PAGE;
        }

        if (Arrays.asList(Index.OUT_OF_SYSTEM_INDICES).contains(
                getSelectedIndex())) {
            FacesMessageUtil.addMessage(getButton(), I18nUtil
                    .getLocalizedMessage("indexcompanylistbean.cantDelete"),
                    FacesMessage.SEVERITY_ERROR);

            return NavigationUtil.SAME_PAGE;
        }

        Index index = getIndexByName(getSelectedIndex());
        if (index == null) {
            FacesMessageUtil.addMessage(getButton(), I18nUtil
                    .getLocalizedMessage("indexcompanylistbean.wrongIndex"),
                    FacesMessage.SEVERITY_ERROR);

            return NavigationUtil.SAME_PAGE;
        }

        if (indexService.remove(index)) {
            setSelectedIndex(null);

            init();

            FacesMessageUtil.addMessage(getButton(), I18nUtil
                    .getLocalizedMessage("indexcompanylistbean.changesSaved"),
                    FacesMessage.SEVERITY_INFO);
        } else {
            FacesMessageUtil
                    .addMessage(
                            getButton(),
                            I18nUtil.getLocalizedMessage("indexcompanylistbean.changesNotSaved"),
                            FacesMessage.SEVERITY_ERROR);
        }

        return NavigationUtil.SAME_PAGE;

    }

}
